package syntax;

import java.awt.Color;
import java.util.Stack;

import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

/**
 * 
 * @author Balazs Pete
 *
 */
public class Coloring extends Thread {

	//stacks storing colors, and used to get current color model
	private Stack<SimpleAttributeSet> colorStack = null;//top of stack is the current color
	private Stack<SimpleAttributeSet> usedColorStack = null;//
	
	//set colors as final
	private final SimpleAttributeSet OPERATOR = new SimpleAttributeSet();
	private final SimpleAttributeSet COMMENTS = new SimpleAttributeSet();	//comments color
	private final SimpleAttributeSet STYLEOPERATOR = new SimpleAttributeSet();
	
	//color levels, if new one is added, son't forget to add it to the initColors() method
	private final SimpleAttributeSet LEVELONE = new SimpleAttributeSet();
	private final SimpleAttributeSet LEVELTWO = new SimpleAttributeSet();
	private final SimpleAttributeSet LEVELTHREE = new SimpleAttributeSet();
	private final SimpleAttributeSet LEVELFOUR = new SimpleAttributeSet();
	private final SimpleAttributeSet LEVELFIVE = new SimpleAttributeSet();
	private final SimpleAttributeSet LEVELSIX = new SimpleAttributeSet();
	
	private boolean bold = false;
	private boolean italics = false;
	
	//initiates an interpreter
	private InterpretCharacter IC = new InterpretCharacter();
	
	public Coloring(){
		initColors();
		
	}
	
	public void run() {

		StyledDocument doc = main.MainWindow.textToDoc();
		int i=0;
		
		while(i<=doc.getLength()){

			String s = null;
			try {
				s = doc.getText(i, 1);
			} catch (BadLocationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			switch(IC.interpret(s)){
			case -1: main.MainWindow.colorCharAtPosition(i, colorStack.peek());break;
			case 0: main.MainWindow.colorCharAtPosition(i, OPERATOR);break;
			case 1: changeLevel(true);main.MainWindow.colorCharAtPosition(i, OPERATOR);break;
			case 2: changeLevel(false);main.MainWindow.colorCharAtPosition(i, OPERATOR);break;
			case 3: commentColoring(true);main.MainWindow.colorCharAtPosition(i, OPERATOR);break;
			case 4: commentColoring(false);main.MainWindow.colorCharAtPosition(i, OPERATOR);break;
			case 5: if(!bold){setBold(true);}else{setBold(false);};main.MainWindow.colorCharAtPosition(i, STYLEOPERATOR);break;
			case 6: if(!italics){setItalics(true);}else{setItalics(false);};main.MainWindow.colorCharAtPosition(i, STYLEOPERATOR);break;
			}
			
			i++;
		}

		if(colorStack.peek()==COMMENTS){
			colorStack.pop();
		}
		while(colorStack.peek()!=LEVELONE){
			colorStack.push(usedColorStack.pop());
		}
		
		setBold(false);
		setItalics(false);
	}
	
	/**
	 * 
	 */
	private void initColors(){
		//set colors here
		OPERATOR.addAttribute(StyleConstants.Foreground, new Color(191,0,255));
		COMMENTS.addAttribute(StyleConstants.Foreground,Color.GRAY);
		STYLEOPERATOR.addAttribute(StyleConstants.Foreground,Color.LIGHT_GRAY);
		LEVELONE.addAttribute(StyleConstants.Foreground,Color.BLACK);
		LEVELTWO.addAttribute(StyleConstants.Foreground,new Color(51,51,136));
		LEVELTHREE.addAttribute(StyleConstants.Foreground,new Color(51,84,204));
		LEVELFOUR.addAttribute(StyleConstants.Foreground,new Color(51,136,238));
		LEVELFIVE.addAttribute(StyleConstants.Foreground,new Color(51,187,170));
		LEVELSIX.addAttribute(StyleConstants.Foreground,new Color(51,204,85));
				
		//add color levels to stack (in reverse order)
		colorStack = new Stack<SimpleAttributeSet>();
		colorStack.add(LEVELSIX);
		colorStack.add(LEVELFIVE);
		colorStack.add(LEVELFOUR);
		colorStack.add(LEVELTHREE);
		colorStack.add(LEVELTWO);
		colorStack.add(LEVELONE);
		
		usedColorStack = new Stack<SimpleAttributeSet>();
	}
	
	private void commentColoring(boolean comment){
		if(comment){
			colorStack.push(COMMENTS);
		} else {
			colorStack.pop();
		}
	}
	
	private void changeLevel(boolean down){
		if(colorStack.peek()!=COMMENTS){
			if(down){
				if(1<colorStack.size()){
					usedColorStack.push(colorStack.pop());
				}
			} else {
				if(0<usedColorStack.size()){
					colorStack.push(usedColorStack.pop());
				}
			}
		}
	}
	
	public void setBold(boolean b){
		bold=b;
		if(b){
			OPERATOR.addAttribute(StyleConstants.Bold, true);
			COMMENTS.addAttribute(StyleConstants.Bold, true);
			LEVELONE.addAttribute(StyleConstants.Bold, true);
			LEVELTWO.addAttribute(StyleConstants.Bold, true);
			LEVELTHREE.addAttribute(StyleConstants.Bold, true);
			LEVELFOUR.addAttribute(StyleConstants.Bold, true);
			LEVELFIVE.addAttribute(StyleConstants.Bold, true);
			LEVELSIX.addAttribute(StyleConstants.Bold, true);
		} else {
			OPERATOR.addAttribute(StyleConstants.Bold, false);
			COMMENTS.addAttribute(StyleConstants.Bold, false);
			LEVELONE.addAttribute(StyleConstants.Bold, false);
			LEVELTWO.addAttribute(StyleConstants.Bold, false);
			LEVELTHREE.addAttribute(StyleConstants.Bold, false);
			LEVELFOUR.addAttribute(StyleConstants.Bold, false);
			LEVELFIVE.addAttribute(StyleConstants.Bold, false);
			LEVELSIX.addAttribute(StyleConstants.Bold, false);
		}
		
	}

	public void setItalics(boolean i){
		italics=i;
		if(i){
			OPERATOR.addAttribute(StyleConstants.Italic, true);
			COMMENTS.addAttribute(StyleConstants.Italic, true);
			LEVELONE.addAttribute(StyleConstants.Italic, true);
			LEVELTWO.addAttribute(StyleConstants.Italic, true);
			LEVELTHREE.addAttribute(StyleConstants.Italic, true);
			LEVELFOUR.addAttribute(StyleConstants.Italic, true);
			LEVELFIVE.addAttribute(StyleConstants.Italic, true);
			LEVELSIX.addAttribute(StyleConstants.Italic, true);
		} else {
			OPERATOR.addAttribute(StyleConstants.Italic, false);
			COMMENTS.addAttribute(StyleConstants.Italic, false);
			LEVELONE.addAttribute(StyleConstants.Italic, false);
			LEVELTWO.addAttribute(StyleConstants.Italic, false);
			LEVELTHREE.addAttribute(StyleConstants.Italic, false);
			LEVELFOUR.addAttribute(StyleConstants.Italic, false);
			LEVELFIVE.addAttribute(StyleConstants.Italic, false);
			LEVELSIX.addAttribute(StyleConstants.Italic, false);
		}
		
	}
}
